/******************************************************************************
 ** File Name:      sprd_musb_host.c                                          *
 ** Author:         hongming.cai                                              *
 ** DATE:           2019/04/13                                                *
 ** Copyright:      2010 Spreatrum, Incoporated. All Rights Reserved.         *
 ** Description:                                                              *
 ******************************************************************************/
/**---------------------------------------------------------------------------*
 **                         Dependencies                                      *
 **---------------------------------------------------------------------------*/

#include <common.h>
#include <asm/io.h>
#include <usb.h>
#include <asm/arch-sharkl3/common.h>
#include <asm/arch-sharkl3/chip_sharkl3/hardware.h>
#include <malloc.h>
#include "sprd_musb2_def.h"
#include "linux/usb/musb.h"
#include "musb_core.h"

#undef BBB_DMA_TRACE

#define WAIT_TIMEOUT_COUNT  1000000
#define HS_MPS_CTRL         64
#define LS_MPS_CTRL         8

#define EP0_MPS             HS_MPS_CTRL

#define TEST_DMA_LNKLIST_NODE_NUM 64
#define MUSB_DMA_MAX_BLKLEN (64*1024 - 1)
#define MAX_RECV_LENGTH     0xffc0 //(64k-64)

static unsigned int mps = 512;
unsigned int Host_DMA_RX_EN[16];
static int bulk_read_init = 0;
static int bulk_write_init = 0;

typedef struct linklist_node_s3
{
	unsigned int   addr;
	unsigned short  frag_len;
	unsigned short  blk_len;
	unsigned int    list_end :1;
	unsigned int    sp :1;
	unsigned int    ioc :1;
	unsigned int    reserved:5;
	unsigned int    ep_num :4;
	unsigned int    pad :20;
#if IS_ENABLED(CONFIG_USB_SPRD_DMA_V3)
	unsigned int reserved2;
#endif
} linklist_node_t3;


PUBLIC __attribute__((aligned (64)))  unsigned char rx_buffer[MAX_RECV_LENGTH];
static struct linklist_node_s3 dma_linklist_rx[TEST_DMA_LNKLIST_NODE_NUM] __attribute__((aligned (64)));
static struct linklist_node_s3 dma_linklist_tx[TEST_DMA_LNKLIST_NODE_NUM] __attribute__((aligned (64)));


static __attribute__((__aligned__(64))) unsigned char read_buf[0x200]={0};
static __attribute__((aligned (64))) unsigned char linklist_ram_tx[sizeof(dma_linklist_tx)];
static __attribute__((aligned (64))) unsigned char linklist_ram_rx[sizeof(dma_linklist_rx)];

extern void usb_enable_module(int en);
extern void Musb_mdelay(uint32_t msecs);
extern void usb_startup(void);


static void __raw_bits_and(unsigned int v, unsigned int a)
{
	__raw_writel((__raw_readl(a) & v), a);
}

static void __raw_bits_or(unsigned int v, unsigned int a)
{
	__raw_writel((__raw_readl(a) | v), a);
}


//ep_type 00:ctrl, 01:isochronous, 10:Bulk, 11:interrupt
void configure_endpoint_host(int dir, char ep_num, unsigned int MPS, unsigned int ep_type, int is_dma_mode, int devnum)
{
	unsigned long cache_start = 0;
	unsigned long cache_end = 0;
	ep_num &=0xf;

#ifdef BBB_DMA_TRACE
	debugf("ep_num = %d, MPS = %d, ep_type = %d, is_dma_mode = %d\n", ep_num, MPS, ep_type, is_dma_mode);
#endif

	(*(volatile unsigned char*)Mentor_USB_INDEX) = ep_num;

	if(dir) { //out
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = devnum;
		(*(volatile unsigned short*)Mentor_USB_INTRTXE) |= (1<<ep_num);
		(*(volatile unsigned char*)Mentor_USB_TX_FIFOS) = 0x6;
		(*(volatile unsigned short*)Mentor_USB_TX_FIFOA) = 8 + (256*ep_num) - 128;
		(*(volatile unsigned short*)Mentor_USB_TXMAXP_) = MPS;
		(*(volatile unsigned char*)Mentor_USB_TXCSRL_) = 0x48; //cLrDataTog
		(*(volatile unsigned char*)Mentor_USB_TXCSRH_) = 0x20; //tx mode
		(*(volatile unsigned char*)Mentor_USB_TXTYPE) = ep_num | (ep_type << 4) | BIT_6;

		if(is_dma_mode)
			(*(volatile unsigned char*)Mentor_USB_TXCSRH_) |= (BIT_2 | BIT_4 | BIT_7);//bit3 force toggle not set

		bulk_write_init = 1;
	} else { //in
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = devnum;
		cache_start = (unsigned long)(&rx_buffer[0]) & ~(ARCH_DMA_MINALIGN - 1);
		cache_end = ALIGN(((unsigned int)rx_buffer + MAX_RECV_LENGTH),ARCH_DMA_MINALIGN);
		invalidate_dcache_range(cache_start, cache_end);

		(*(volatile unsigned short*)Mentor_USB_INTRRXE) |= (1<<ep_num);
		(*(volatile unsigned char*)Mentor_USB_RX_FIFOS) = 0x6;
		(*(volatile unsigned short*)Mentor_USB_RX_FIFOA) = 8 + (256*ep_num);
		(*(volatile unsigned short*)Mentor_USB_RXMAXP_) = MPS;
		(*(volatile unsigned char*)Mentor_USB_RXCSRH_) = 0;
		(*(volatile unsigned char*)Mentor_USB_RXCSRL_) = 0x90; //cLrDataTog
		(*(volatile unsigned char*)Mentor_USB_RXTYPE) = ep_num | (ep_type << 4) | BIT_6;

		if(is_dma_mode) {
			(*(volatile unsigned char*)Mentor_USB_RXCSRH_) |= (BIT_3 | BIT_5 | BIT_7);
			Host_DMA_RX_EN[ep_num] = 0;
		}

		bulk_read_init = 1;
	}
}

static void usb_host_boot_enable(unsigned int enable)
{
	unsigned int regVal = 0;

	usb_startup();
	__raw_bits_and(~BIT_3, REG_AP_AHB_OTG_PHY_CTRL); //USB2_PHY_IDDIG, for host, ID should be 0

	Musb_mdelay(100);

	regVal = __raw_readl(REG_AP_AHB_OTG_PHY_TUNE);
	debugf("REG_AP_AHB_OTG_PHY_TUNE = 0x%x\n",regVal);
	regVal &= ~(0x3 << 8);
	regVal &= ~(0x0f <<12);
	regVal |= (0x02 << 8);
	regVal |= (0x08 << 12);
	__raw_writel(regVal, REG_AP_AHB_OTG_PHY_TUNE);

	Musb_mdelay(100);
	__raw_bits_or(BIT_4|BIT_5|BIT_6, REG_AP_AHB_AHB_RST); //reset usb otg phy, reset usb otg utmi,reset usb otg
	Musb_mdelay(100);
	__raw_bits_and(~(BIT_4|BIT_5|BIT_6), REG_AP_AHB_AHB_RST);

	__raw_bits_or(BIT_22|BIT_24, REG_AP_AHB_OTG_PHY_TEST);   //vbus valid for ctrl
	__raw_bits_or(BIT_29|BIT_30, REG_AP_AHB_OTG_PHY_CTRL);   //utmi width select

	__raw_bits_and(~BIT_3, REG_AP_AHB_OTG_PHY_CTRL);    //USB2_PHY_IDDIG, for host, ID should be 0
}

static void usb_host_core_init(void)
{
	debugf("usb_core_init\n");
	(*(volatile unsigned char*)Mentor_OTG_EXT_CSI) = 0x01;  //force host mode
	(*(volatile unsigned char*)Mentor_USB_POWER) = 0x20;    //enter suspend mode
	(*(volatile unsigned char*)Mentor_USB_INTRUSBE) = 0xff; //enable all interrupts
	bulk_write_init = 0;
	bulk_read_init = 0;
}

static int control_host_zero(unsigned char* buf)
{
	volatile unsigned char reg8;
	volatile unsigned char i;
	int timeout = WAIT_TIMEOUT_COUNT;

	//write fifo
	for (i = 0; i < 8; i++)
		*(volatile unsigned char*)Mentor_USB_EP0_FIFO = (buf[i]);

	//send setup pkt
	*(volatile unsigned char*)Mentor_USB_CSR0L |= (BIT_1 | BIT_3);

	//wait int
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	while(((reg8 & BIT_0) != BIT_0)&&timeout)
	{
		timeout--;
		udelay(10);
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	}
	debugf("control_host_zero\n");
	if(!timeout)
	{
		printf("wait tx int1 timeout\n");
		return -1;
	}
	timeout = WAIT_TIMEOUT_COUNT;
	//check
	reg8 = *(volatile unsigned char*)Mentor_USB_CSR0L;
	if(reg8 & (BIT_2 | BIT_4 | BIT_7))
	{
		printf("EP0 setup in error: 0x%x\n", reg8);
		return -1;
	}

	//send IN token state
	*(volatile unsigned char*)Mentor_USB_CSR0L |= (BIT_5 | BIT_6);

	//wait int
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	while((((reg8 & BIT_0) != BIT_0))&&timeout)
	{
		timeout--;
		udelay(10);
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	}
	if(!timeout)
	{
		printf("wait tx int2 timeout\n");
		return -1;
	}

	//check
	reg8 = *(volatile unsigned char*)Mentor_USB_CSR0L;
	if(reg8 & (BIT_2 | BIT_4 | BIT_7))
	{
		printf("EP0 status in error: 0x%x\n", reg8);
		return -2;
	}

	//clear
	*(volatile unsigned char*)Mentor_USB_CSR0L &= (~(BIT_0 | BIT_6));

	return 0;
}

static int control_host_reads(unsigned char* buf, unsigned char* buf_read, unsigned int* read_len, unsigned int ep0_mps)
{
	volatile unsigned char reg8;
	volatile unsigned short reg16;
	volatile unsigned char i;
	volatile unsigned int data_in_cnt = 0;
	unsigned char *data = buf_read;
	//clear Nak Timeout, Error and Rxstall
	*(volatile unsigned char*)Mentor_USB_CSR0L &= (~(BIT_2 | BIT_4 | BIT_7));
	int timeout = WAIT_TIMEOUT_COUNT;


	debug("\n");
	for (i = 0; i < 8; i++)
		debug(" 0x%x", buf[i]);
	debug("\n");

	//write fifo
	for (i = 0; i < 8; i++)
		*(volatile unsigned char*)Mentor_USB_EP0_FIFO = (buf[i]);

	//send setup pkt
	*(volatile unsigned char*)Mentor_USB_CSR0L |= (BIT_1 | BIT_3);

	//wait int
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	while(((reg8 & BIT_0) != BIT_0)&&timeout)
	{
		timeout--;
		udelay(10);
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	}
	if(!timeout)
	{
		printf("control_host_reads wait tx int1 timeout\n");
		return -1;
	}
	timeout = WAIT_TIMEOUT_COUNT;

	//check
	reg8 = *(volatile unsigned char*)Mentor_USB_CSR0L;
	if (reg8 & (BIT_2 | BIT_4 | BIT_7))
	{
		printf("EP0 SETUP error: 0x%x\n", reg8);
		return -1;
	}
Data_IN:
	//send in and receive
	*(volatile unsigned char*)Mentor_USB_CSR0L |= (BIT_5);

	//wait int
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	while(((reg8 & BIT_0) != BIT_0)&&timeout)
	{
		timeout--;
		udelay(10);
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	}
	if(!timeout)
	{
		printf("control_host_reads wait tx int2 timeout\n");
		return -1;
	}
	timeout = WAIT_TIMEOUT_COUNT;

	//check
	reg8 = *(volatile unsigned char*)Mentor_USB_CSR0L;
	if (reg8 & (BIT_2 | BIT_4 | BIT_7))
	{
		printf("EP0 Data in error: 0x%x\n", reg8);
		return -2;
	}

	//load fifo
	reg16 = *(volatile unsigned short*)Mentor_USB_COUNT0;
	data_in_cnt += reg16;
	debug("Data received: %u\n", reg16);
	for (i = 0; i < reg16; i++) {
		read_buf[i] = *(volatile unsigned char*)Mentor_USB_EP0_FIFO;
		if(i && !(i%8))
			debug("\n");
		debug(" 0x%x", read_buf[i]);
	}
	memcpy(data, read_buf, reg16);
	data += reg16;
	debug("\n");

	//clear
	*(volatile unsigned char*)Mentor_USB_CSR0L &= (~BIT_0);
	if((reg16 == ep0_mps)&&(data_in_cnt < (buf[6] + buf[7]*256)))
		goto Data_IN;
	//send out state
	*(volatile unsigned char*)Mentor_USB_CSR0L |= (BIT_1 | BIT_6);

	//wait int
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	while(((reg8 & BIT_0) != BIT_0)&&timeout)
	{
		timeout--;
		udelay(10);
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRTX;
	}
	if(!timeout)
	{
		printf("control_host_reads wait tx int3 timeout\n");
		return -1;
	}
	//check
	reg8 = *(volatile unsigned char*)Mentor_USB_CSR0L;
	if (reg8 & (BIT_2 | BIT_4 | BIT_7))
	{
		printf("EP0 status in error: 0x%x\n", reg8);
		return -3;
	}

	//clear
	*(volatile unsigned char*)Mentor_USB_CSR0L &= (~BIT_6);

	*read_len = data_in_cnt;

	return 0;
}



int usb_reset_root_port(void)
{
	(*(volatile unsigned char*)Mentor_USB_POWER) |= BIT_3;
	Musb_mdelay(50);    //reset signal at least 20ms
	(*(volatile unsigned char*)Mentor_USB_POWER) &= (~BIT_3);
	Musb_mdelay(200);
	return 0;
}




static void usb_device_detect(void)
{
	volatile unsigned char reg8;


	(*(volatile unsigned char*)Mentor_USB_DEVCTL) |= BIT_0; //start a session

	printf("waiting for usb device connection...\n");
	//wait int of device connection
	reg8 = *(volatile unsigned char*)Mentor_USB_INTRUSB;
	while((reg8 & BIT_4) != BIT_4)
		reg8 = *(volatile unsigned char*)Mentor_USB_INTRUSB;
	printf("detect device connected\n");
	usb_reset_root_port();
	printf("Reset device done 0x%x\n", *(volatile unsigned char*)Mentor_USB_POWER);

	reg8 = *(volatile unsigned char*)Mentor_USB_POWER;
	if(reg8 & BIT_4)
		printf("USB running in HS mode, Mentor_USB_POWER = 0x%x\n", reg8);
	else
		printf("USB running in FS mode, Mentor_USB_POWER = 0x%x\n", reg8);

	Musb_mdelay(200);
}

void configure_ep0_host(void)
{
	(*(volatile unsigned char*)Mentor_USB_INDEX) = 0; //select endpoint number 0;
	(*(volatile unsigned char*)Mentor_USB_FADDR) = 0; //set function address in host mode
}
int musb_host_read(int ep, int transfer_size, unsigned int *buffer)
{
	int rx_ch;
	unsigned int rx_len;
	int index = 0;
	int offset = 0;
	int endpktoffset = 0;
	int endone = 0;
	unsigned int list_end = 0;
	unsigned long cache_start = 0;
	unsigned long cache_end = 0;
	unsigned int cache_len;
	uint32_t len;
	unsigned int int_status;
	unsigned int mts = MUSB_DMA_MAX_BLKLEN;
	int timeout = WAIT_TIMEOUT_COUNT;
#ifdef BBB_DMA_TRACE
	printf("musb_host_read ep=%d,transfer_size=%d\r\n",ep,transfer_size);
#endif
	if ((transfer_size%512 == 0) && (transfer_size > 512)) {
		rx_len = transfer_size - 512;
	}
	else if (transfer_size == 512){
		rx_len = 512;
	}
	else{
		rx_len = transfer_size;
	}
	if (index > 31) {
		printf("linklist size overflow\r\n");
		return -1;
	}
	(*(volatile unsigned char*)Mentor_USB_INDEX) = ep;
	if(Host_DMA_RX_EN[ep] == 0) {
		if (transfer_size > 512 )
			(*(volatile unsigned char*)Mentor_USB_RXCSRH(ep)) |= (BIT_6);
		else
			(*(volatile unsigned char*)Mentor_USB_RXCSRH(ep)) &= ~(BIT_6);
		(*(volatile unsigned char*)Mentor_USB_RXCSRL(ep)) |= (BIT_5);
readagain:
		Host_DMA_RX_EN[ep] = 1;
	}
	cache_start = (unsigned long)buffer & ~(ARCH_DMA_MINALIGN - 1);
	cache_end = ALIGN(((unsigned int)buffer + transfer_size),ARCH_DMA_MINALIGN);
	invalidate_dcache_range(cache_start, cache_end);

	cache_start = (unsigned long)linklist_ram_rx & ~(ARCH_DMA_MINALIGN - 1);
	cache_end = ALIGN(((unsigned int)linklist_ram_rx + sizeof(linklist_ram_rx)),ARCH_DMA_MINALIGN);
	invalidate_dcache_range(cache_start, cache_end);
	memset(linklist_ram_rx,0,sizeof(linklist_ram_rx));
	offset = 0;
	for( index = 0; rx_len; ++index) {
		dma_linklist_rx[index].addr = (unsigned int)(buffer) + offset + endpktoffset;
		dma_linklist_rx[index].frag_len = 32;
		dma_linklist_rx[index].sp = 0;
		if((rx_len > mts)&&(index < TEST_DMA_LNKLIST_NODE_NUM - 1)) {
			dma_linklist_rx[index].blk_len = mts;
			dma_linklist_rx[index].ioc = 0;
			dma_linklist_rx[index].list_end = 0;
			rx_len -= mts;
			offset += mts;
		} else {
			dma_linklist_rx[index].blk_len = rx_len;
			dma_linklist_rx[index].ioc = 1;
			dma_linklist_rx[index].list_end = 1;
			rx_len = 0;
			list_end = 1;
		}
	}
	index = index - 1;
#ifdef BBB_DMA_TRACE
	printf("dma_linklist_rx[%d].blk_len=%d\n",index,dma_linklist_rx[index].blk_len);
	printf("dma_linklist_rx[%d].addr=%p\n",index,dma_linklist_rx[index].addr);
#endif
	if (list_end) {
		memcpy(linklist_ram_rx, (unsigned char *)dma_linklist_rx,
				(index + 1)*sizeof(dma_linklist_rx[0]));
		if (!index)
			len = 64;
		else
			len = sizeof(dma_linklist_rx);
		cache_start = (unsigned long)(dma_linklist_rx);
		cache_end = cache_start + (unsigned long)len;
		invalidate_dcache_range(cache_start, cache_end);

		cache_start = (unsigned long)(linklist_ram_rx);
		cache_end = cache_start + (unsigned long)len;
		invalidate_dcache_range(cache_start, cache_end);

		//out ep for receive data
		rx_ch = ep + 15;
		//enable linklist end rx last interrupt
		REG32(MUSB_DMA_CHN_INTR(rx_ch)) |= 0x14;
		//set linklist pointer
		REG32(MUSB_DMA_CHN_LLIST_PTR(rx_ch)) = (uint32_t)linklist_ram_rx;
		//enable channel and trigger rx dma transfer
		REG32(MUSB_DMA_CHN_CFG(rx_ch)) |= 0x1;

		/* polling Channel Link list Masked interrupt status */
		do {
			udelay(10);
			timeout--;
			int_status = REG32(MUSB_DMA_CHN_INTR(rx_ch));
		}while(((int_status & BIT_18) == 0) &&
				((int_status & BIT_20) == 0) && timeout);

		if(!timeout)
		{
			printf("musb_host_read wait DMA int timeout\n");
			Host_DMA_RX_EN[ep] = 0;
			return -1;
		}
		/* clear interrupt */
		Host_DMA_RX_EN[ep] = 0;
		REG32(MUSB_DMA_CHN_INTR(rx_ch)) |= 0x14000000;
		if ((transfer_size%512 == 0) && (transfer_size > 512) && endone == 0) {
			(*(volatile unsigned char*)Mentor_USB_RXCSRH(ep)) &= ~(BIT_6);
			endone = 1;
			endpktoffset = transfer_size - 512;
			rx_len=512;
			goto readagain;
		}
		return 0;
	}
}
int musb_host_write(int ep, int transfer_size, unsigned int *buffer)
{
	int tx_ch;
	unsigned int tx_len = transfer_size;
	int index = 0;
	int offset = 0;
	unsigned int list_end = 0;
	unsigned long cache_start = 0;
	unsigned long cache_end = 0;
	unsigned int cache_len;
	uint32_t len;
	unsigned int int_status;
	unsigned int mts = MUSB_DMA_MAX_BLKLEN;
	int timeout = WAIT_TIMEOUT_COUNT;
#ifdef BBB_DMA_TRACE
	printf("musb_host_write ep=%d,transfer_size=%d\r\n",ep,transfer_size);
#endif

	if (index > 31) {
		printf("linklist size overflow\r\n");
		return -1;
	}
	(*(volatile unsigned char*)Mentor_USB_INDEX) = ep;

	cache_start = (uint64_t)buffer;
	if (transfer_size % 64)
		len = transfer_size - (transfer_size % 64) + 64;
	else
		len = transfer_size;
	cache_end = cache_start + len;
	flush_dcache_range(cache_start, cache_end);
	offset = 0;
	for ( index = 0; tx_len ; ++index) {
		dma_linklist_tx[index].addr =(unsigned int)(buffer) + offset;
		dma_linklist_tx[index].frag_len = 32;
		dma_linklist_tx[index].sp = 0;
		if ((tx_len > mts)&&(index < TEST_DMA_LNKLIST_NODE_NUM-1)) {
			dma_linklist_tx[index].blk_len = mts;
			dma_linklist_tx[index].ioc = 0;
			dma_linklist_tx[index].list_end = 0;
			tx_len -= mts;
			offset += mts;
		} else {
			dma_linklist_tx[index].blk_len = tx_len;
			dma_linklist_tx[index].ioc = 1;
			dma_linklist_tx[index].list_end = 1;
			tx_len = 0;
			list_end = 1;
		}
	}
	index = index - 1;
	memcpy(&linklist_ram_tx, (unsigned char *)&dma_linklist_tx,
			(index + 1)*sizeof(dma_linklist_tx[0]));

	len = (index + 1)*64;
	cache_start = (unsigned long)(&dma_linklist_tx);
	cache_end = cache_start + (unsigned long)len;
	flush_dcache_range(cache_start, cache_end);

	cache_start = (unsigned long)(&linklist_ram_tx);
	cache_end = cache_start + (unsigned long)len;
	flush_dcache_range(cache_start, cache_end);
	tx_ch = ep;
	//enable linklist end interrupt
	REG32(MUSB_DMA_CHN_INTR(tx_ch)) |= 0x04;
	//set linklist pointer
	REG32(MUSB_DMA_CHN_LLIST_PTR(tx_ch)) = (uint32_t)linklist_ram_tx;
	//enable channel and trigger rx dma transfer
	REG32(MUSB_DMA_CHN_CFG(tx_ch)) |= 0x1;
	//polling linklist end int
	int_status=REG32(MUSB_DMA_CHN_INTR(tx_ch));
	while((int_status & BIT_18) == 0 && timeout) {
		udelay(10);
		timeout--;
		int_status=REG32(MUSB_DMA_CHN_INTR(tx_ch));
	}
	if(!timeout)
	{
		printf("musb_host_write wait DMA int timeout\n");
		return -1;
	}

	//clear tx linklist end int
	REG32(MUSB_DMA_CHN_INTR(tx_ch)) |= BIT_26;
	return 0;
}

int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
#ifdef CONFIG_FAN54015_CHARGE_IC
	fan54015_otg_enable(1);
#endif
	mdelay(1000);

	usb_host_boot_enable(1);
	usb_host_core_init();
	configure_ep0_host();
	usb_device_detect();

	return 0;
}

int usb_lowlevel_stop(int index)
{
	usb_enable_module(0);
	return 0;
}


int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, struct devrequest *setup)
{
	unsigned long start_addr;
	unsigned long end_addr;
	unsigned char* cmd = (unsigned char*)setup;
	int ep = usb_pipeendpoint(pipe);
	int devnum = usb_pipedevice(pipe);
	int err = 0;
	unsigned int read_len = 0;
#ifdef BBB_DMA_TRACE
	debugf("addr%d-ep%d:0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
			devnum, ep, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7]);
#endif

	usb_settoggle(dev, ep, 1, 0);

	dev->status = 0;

	if (usb_pipein(pipe)) {
		err = control_host_reads((unsigned char*)setup, (unsigned char*)buffer, &read_len,EP0_MPS);
		dev->act_len = read_len;
		debugf("dev->act_len = %d\n", read_len);
	} else {
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = devnum;
		err = control_host_zero((unsigned char*)setup);
		dev->act_len = transfer_len;
		//debugf("devnum = %d\n", devnum);
	}

	if(err < 0)
		goto ERROR;

	if(setup->request == USB_REQ_SET_ADDRESS)
	{
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = devnum;
		(*(volatile unsigned char*)Mentor_USB_FADDR) = setup->value;
	}

	return 0;

ERROR:
	dev->status = USB_ST_STALLED;
	dev->act_len = 0;
	return err;
}


int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,void *buffer, int transfer_len)
{
	int ep = usb_pipeendpoint(pipe);
	int max_pkt_size = usb_maxpacket(dev, pipe);
	int dir_out = usb_pipeout(pipe);
	int err = 0;

	dev->status = 0;
#ifdef BBB_DMA_TRACE
	printf("submit_bulk_msg:addr=%d, ep=%d, max_pkt_size=%d, dir=%d\n", dev->devnum, ep, max_pkt_size, dir_out);
#endif
	(*(volatile unsigned char*)Mentor_USB_INDEX) = ep;
	if((dir_out && (bulk_write_init == 0)) || ((!dir_out)&&(bulk_read_init == 0)))
		configure_endpoint_host(dir_out, ep, max_pkt_size, 2, 1, dev->devnum);

	if(dir_out) {
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = dev->devnum;
		err = musb_host_write((unsigned int)ep, transfer_len, buffer);
	} else {
		//(*(volatile unsigned char*)Mentor_USB_FADDR) = dev->devnum;
		err = musb_host_read((unsigned int)ep, transfer_len, buffer);
	}

	if(err < 0)
	{
		goto ERROR;
	}

	dev->act_len = transfer_len;

	return 0;
ERROR:
	dev->act_len = 0;
	dev->status = USB_ST_STALLED;
	return err;
}

int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, int interval)
{
	return 0;
}
